﻿// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. 
// See License.txt in the project root for license information.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Actors;
using System.Threading.Actors.Helpers;
using System.Threading.Tasks;

namespace TestActorMethods
{
    [TestClass]
    public class DictionaryActorUnitTests
    {
        // Helper methods
        private String _dictionaryName = "TestDictionary";

        private Object[] P(params Object[] parameters)
        {
            Object[] array = new Object[parameters.Length + 1];
            array[0] = _dictionaryName;
            Array.Copy(parameters, 0, array, 1, parameters.Length);
            return array;
        }

        [TestMethod]
        public void Dictionary_ClearTest()
        {
            Console.WriteLine("Testing Dictionary's clear.");
            IActorState dict = ActorUnitTests.CreateActorState();

            DictionaryActorMethods.TryConstruct(dict, P(typeof(String).FullName, typeof(Int32).FullName));

            Assert.AreEqual(DictionaryActorMethods.Set(dict, P("0", 0)), 1);
            Assert.AreEqual(DictionaryActorMethods.Set(dict, P("1", 1)), 1);
            Assert.AreEqual(DictionaryActorMethods.Set(dict, P("0", -1)), 0);

            Assert.IsNull(DictionaryActorMethods.Clear(dict, P()));
            Assert.AreEqual(DictionaryActorMethods.Count(dict, P()), 0);
            Assert.IsNull(DictionaryActorMethods.Clear(dict, P()));  // Calling Clear a second time.

            // Must flush the state for the dictionary...
            var waiter = dict.Flush();
            if (waiter != null) waiter.Wait();

            // This is checking the actor state for extra, dangling items.  IE, if Clear leaks
            // nodes into our IActorState, we should know about it.  If this fails though, it could
            // be because we've added a new "field" to IActorState or some other reasonable issue.
            // Feel free to update the number below.
            if (dict is StandaloneActorState)
            {
                const int NumKnownFieldsAndInstanceSpecificMethodsInDictionaryActor = 4;
                int numItemsInState = ((StandaloneActorState)dict).NumItemsInState;
                if (numItemsInState != NumKnownFieldsAndInstanceSpecificMethodsInDictionaryActor)
                    throw new Exception(String.Format("Warning: Update this if you've added or removed \"fields\" from the actor.  After calling Clear, expected " +
                                                      "all state to be freed, except for the {0} fields & instance-specific methods used by DictionaryActor.  Number of items left in state: {1}",
                                                      NumKnownFieldsAndInstanceSpecificMethodsInDictionaryActor, numItemsInState));
            }

            Assert.IsNull(DictionaryActorMethods.Destroy(dict, P()));
            waiter = dict.Flush();
            if (waiter != null) waiter.Wait();

            // Ensure that all our fields are erased.
            if (dict is StandaloneActorState)
            {
                int numItemsInState = ((StandaloneActorState)dict).NumItemsInState;
                if (numItemsInState != 0)
                    throw new Exception(String.Format("After Destroying the dictionary, there is at least one piece of state left in the IActorState.  Number of items leaked: {0}",
                                                      numItemsInState));
            }
        }

        [TestMethod]
        public void Dictionary_ContainsTest()
        {
            Console.WriteLine("Testing Contains.");
            IActorState dict = ActorUnitTests.CreateActorState();

            DictionaryActorMethods.TryConstruct(dict, P(typeof(String).FullName, typeof(String).FullName));

            Assert.IsFalse((bool) DictionaryActorMethods.ContainsKey(dict, P("Hello")));
            Assert.IsFalse((bool)DictionaryActorMethods.ContainsKey(dict, P("Konnichiwa")));
            Assert.AreEqual(1, (int)DictionaryActorMethods.Set(dict, P("Hello", "World")));
            Assert.IsTrue((bool) DictionaryActorMethods.ContainsKey(dict, P("Hello")));
            Assert.IsFalse((bool)DictionaryActorMethods.ContainsKey(dict, P("Konnichiwa")));

            Assert.AreEqual(1, (int)DictionaryActorMethods.Set(dict, P("Konnichiwa", "In Japanese")));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(dict, P("Hello")));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(dict, P("Konnichiwa")));

            // Now add and remove an element to ensure Contains doesn't return the wrong value.
            Assert.AreEqual(1, (int)DictionaryActorMethods.Set(dict, P("Guten Tag", "In German")));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(dict, P("Hello")));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(dict, P("Konnichiwa")));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(dict, P("Guten Tag")));
            Assert.AreEqual(3, DictionaryActorMethods.Count(dict, P()));

            // Remove and re-check
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(dict, P("Guten Tag")));
            Assert.IsFalse((bool)DictionaryActorMethods.ContainsKey(dict, P("Guten Tag")));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(dict, P("Hello")));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(dict, P("Konnichiwa")));

            Assert.AreEqual(2, DictionaryActorMethods.Count(dict, P()));

            var pairs = (IList<KeyValuePair<String, Object>>)DictionaryActorMethods.Enumerate(dict, P());
            Assert.IsNotNull(pairs);
            Assert.AreEqual(2, pairs.Count, "Expected Enumerate to return the count number of elements, ie, a list of KeyValuePair<String, Object>");
            int numFound = 0;
            bool containsHello = false, containsKonnichiwa = false;
            for(int i=0; i<pairs.Count; i++)
            {
                String key = pairs[i].Key;
                Object value = pairs[i].Value;
                numFound++;
                if (key.Equals("Hello"))
                {
                    containsHello = true;
                    Assert.AreEqual("World", value);
                }
                else if (key.Equals("Konnichiwa"))
                {
                    containsKonnichiwa = true;
                    Assert.AreEqual("In Japanese", value);
                }
                else
                {
                    Assert.Fail("Why am I here?  Enumeration returned something unexpected!  Pair: {0} / {1}", key, value);
                }
            }
            Assert.IsTrue(containsHello, "Couldn't find Hello in the return value from Enumerate!");
            Assert.IsTrue(containsKonnichiwa, "Couldn't find Konnichiwa in the return value from Enumerate!");
            Assert.AreEqual(2, numFound, "Found an unexpected number of items in the return value from Enumerate!");
        }


        [TestMethod]
        public void Dictionary_SetGet()
        {
            Console.WriteLine("Testing dictionary set and get.");
            IActorState state = ActorUnitTests.CreateActorState();

            DictionaryActorMethods.TryConstruct(state, new string[] { "dictionary1", typeof(String).FullName, typeof(String).FullName });
            DictionaryActorMethods.TryConstruct(state, new string[] { "dictionary2", typeof(String).FullName, typeof(String).FullName });

            // check get for non-exist key
            Assert.IsNull(DictionaryActorMethods.Get(state, new string[] { "dictionary1", "item1" }));

            Assert.AreEqual(1, (int)DictionaryActorMethods.Set(state, new string[] { "dictionary1", "item1", "val1" }));
            Assert.AreEqual("val1", DictionaryActorMethods.Get(state, new string[] { "dictionary1", "item1" }));
            Assert.IsNull(DictionaryActorMethods.Get(state, new string[] { "dictionary1", "item2" }));   

            // different keys
            Assert.AreEqual(1, (int)DictionaryActorMethods.Set(state, new string[] { "dictionary2", "item1", "val1_2" }));
            Assert.AreEqual("val1", DictionaryActorMethods.Get(state, new string[] { "dictionary1", "item1" }));
            Assert.AreEqual("val1_2", DictionaryActorMethods.Get(state, new string[] { "dictionary2", "item1" }));

            // update existing item
            Assert.AreEqual(0, (int)DictionaryActorMethods.Set(state, new string[] { "dictionary1", "item1", "val1u" }));
            Assert.AreEqual("val1u", DictionaryActorMethods.Get(state, new string[] { "dictionary1", "item1" }));

            // set new only
            Assert.AreEqual(0, (int)DictionaryActorMethods.Set(state, new string[] { "dictionary1", "item1", "val1" }));
            Assert.AreEqual(1, (int)DictionaryActorMethods.Set(state, new string[] { "dictionary1", "item5", "val1" }));
        }

        [TestMethod]
        public void Dictionary_Remove()
        {
            Console.WriteLine("Testing dictionary remove.");
            IActorState state = ActorUnitTests.CreateActorState();

            DictionaryActorMethods.TryConstruct(state, new Object[] { "dict1", typeof(String).FullName, typeof(String).FullName });

            Assert.AreEqual(1, (int)DictionaryActorMethods.Set(state, new Object[] { "dict1", "item1", "val1" }));

            // remove exist and remove not exist
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, new Object[] { "dict1", "item1" }));
            Assert.AreEqual(0, (int)DictionaryActorMethods.Remove(state, new Object[] { "dict1", "item1" }));

            Assert.AreEqual(0, (int)DictionaryActorMethods.Remove(state, new Object[] { "dict1", "item_not_in_dictionary" }));

            Assert.AreEqual(0, DictionaryActorMethods.Count(state, new Object[] { "dict1" }));

            // Add one item, call Set to update that item and add some new items, then remove them.
            DictionaryActorMethods.Set(state, new Object[] { "dict1", "item1", "val1u" });
            Object[] manyItems = new Object[] { "dict1", "item1", 1, "item2", 2, "item3", 3, "item4", 4, "item5", 5 };
            DictionaryActorMethods.Set(state, manyItems);
            Assert.AreEqual(5, DictionaryActorMethods.Count(state, new Object[] { "dict1" }));

            Assert.AreEqual(1, DictionaryActorMethods.Get(state, new Object[] { "dict1", "item1" }));
            Assert.AreEqual(2, DictionaryActorMethods.Get(state, new Object[] { "dict1", "item2" }));
            Assert.AreEqual(3, DictionaryActorMethods.Get(state, new Object[] { "dict1", "item3" }));
            Assert.AreEqual(4, DictionaryActorMethods.Get(state, new Object[] { "dict1", "item4" }));
            Assert.AreEqual(5, DictionaryActorMethods.Get(state, new Object[] { "dict1", "item5" }));

            Assert.AreEqual(0, (int)DictionaryActorMethods.Remove(state, new Object[] { "dict1", "not_in_dictionary" }));
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, new Object[] { "dict1", "item5" }));
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, new Object[] { "dict1", "item2" }));
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, new Object[] { "dict1", "item1" }));
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, new Object[] { "dict1", "item4" }));
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, new Object[] { "dict1", "item3" }));

            Assert.AreEqual(0, DictionaryActorMethods.Count(state, new Object[] { "dict1" }));
        }

        [TestMethod]
        public void Dictionary_MultiGetSet()
        {
            Console.WriteLine("Testing dictionary MultiGet and Set operations.");
            IActorState state = ActorUnitTests.CreateActorState();

            DictionaryActorMethods.TryConstruct(state, P(typeof(String).FullName, typeof(Int32).FullName));

            Object[] manyItems = new Object[] { _dictionaryName, "item1", 1, "item2", 2, "item3", 3, "item4", 4, "item5", 5 };
            DictionaryActorMethods.Set(state, manyItems);
            Assert.AreEqual(5, DictionaryActorMethods.Count(state, P()));

            IList<Object> values = (IList<Object>)DictionaryActorMethods.MultiGet(state, P("item1", "item2", "item3", "item5"));
            Assert.IsNotNull(values);
            Assert.AreEqual(4, values.Count);
            Assert.AreEqual(1, values[0]);
            Assert.AreEqual(2, values[1]);
            Assert.AreEqual(3, values[2]);
            Assert.AreEqual(5, values[3]);

            DictionaryActorMethods.Remove(state, P("item1", "item3", "item5"));
            Assert.AreEqual(2, DictionaryActorMethods.Count(state, P()), "Count after removing 3 items should be 2");
            Assert.AreEqual(2, DictionaryActorMethods.Get(state, P("item2")));
            Assert.AreEqual(4, DictionaryActorMethods.Get(state, P("item4")));
        }


        [TestMethod]
        public void Dictionary_ContainsKeyAndCount()
        {
            Console.WriteLine("Testing Dictionary ContainsKey and Count.");
            IActorState state = ActorUnitTests.CreateActorState();

            DictionaryActorMethods.TryConstruct(state, P(typeof(String).FullName, typeof(String).FullName));

            // check get for non-exist key
            Assert.AreEqual(0, DictionaryActorMethods.Count(state, P()));
            Assert.IsFalse((bool)DictionaryActorMethods.ContainsKey(state, P("item1")));

            // check get for exist key
            Assert.AreEqual(1, (int)DictionaryActorMethods.Set(state, P("item1", "val1")));
            Assert.AreEqual(1, (int) DictionaryActorMethods.Count(state, P()));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(state, P("item1")));
            Assert.IsFalse((bool)DictionaryActorMethods.ContainsKey(state, P("item2")));

            DictionaryActorMethods.Set(state, P("item1", "val1", "item2", "val2", "item3", "val3", 
                                                     "item4", "val4", "item5", "val5"));
            Assert.AreEqual(5, (int)DictionaryActorMethods.Count(state, P()));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(state, P("item1")));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(state, P("item2")));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(state, P("item3")));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(state, P("item4")));
            Assert.IsTrue((bool)DictionaryActorMethods.ContainsKey(state, P("item5")));            

            // after remove
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, P("item1")));
            Assert.AreEqual(4, (int)DictionaryActorMethods.Count(state, P()));
            Assert.IsFalse((bool)DictionaryActorMethods.ContainsKey(state, P("item1")));

            Assert.AreEqual(0, (int)DictionaryActorMethods.Remove(state, P("item1")));
            Assert.AreEqual(4, (int)DictionaryActorMethods.Count(state, P()));

            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, P("item2")));
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, P("item3")));
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, P("item4")));
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, P("item5")));
            Assert.AreEqual(0, (int)DictionaryActorMethods.Count(state, P()));
        }

        [TestMethod]
        public void Dictionary_EnumerateTest()
        {
            Console.WriteLine("Testing Dictionary enumerate fields and values.");
            IActorState state = ActorUnitTests.CreateActorState();

            DictionaryActorMethods.TryConstruct(state, P(typeof(String).FullName, typeof(Int32).FullName));

            // check enum for empty dictionary
            ListIsEmpty((IList<String>)DictionaryActorMethods.EnumKeys(state, P()));
            ListIsEmpty((IList<Object>)DictionaryActorMethods.EnumValues(state, P()));

            // check enum for exist key
            Assert.AreEqual(1, (int)DictionaryActorMethods.Set(state, P("item1", 1)));
            ListsAreEqual(new KeyValuePair<String, Object>[] { new KeyValuePair<String, Object>("item1", 1) }, DictionaryActorMethods.Enumerate(state, P()));
            ListsAreEqual(new String[] { "item1" }, DictionaryActorMethods.EnumKeys(state, P()));
            ListsAreEqual(new Object[] { 1 }, DictionaryActorMethods.EnumValues(state, P()));

            DictionaryActorMethods.Set(state, P("item2", 2, "item3", 3, "item4", 4, "item5", 5));
            Assert.AreEqual(5, DictionaryActorMethods.Count(state, P()));
            ListsAreEqualUnordered(new KeyValuePair<String, Object>[] { new KeyValuePair<String, Object>("item1", 1), 
                                       new KeyValuePair<String, Object>("item2", 2), new KeyValuePair<String, Object>("item3", 3), 
                                       new KeyValuePair<String, Object>("item4", 4), new KeyValuePair<String, Object>("item5", 5) },
                                   DictionaryActorMethods.Enumerate(state, P()));
            ListsAreEqualUnordered(new String[] { "item1", "item2", "item3", "item4", "item5" },
                                   DictionaryActorMethods.EnumKeys(state, P()));
            ListsAreEqualUnordered(new Object[] { 1, 2, 3, 4, 5 },
                                   DictionaryActorMethods.EnumValues(state, P()));

            // after remove
            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, P("item1")));
            ListsAreEqualUnordered(new KeyValuePair<String, Object>[] { new KeyValuePair<String, Object>("item2", 2),
                                       new KeyValuePair<String, Object>("item3", 3), new KeyValuePair<String, Object>("item4", 4),
                                       new KeyValuePair<String, Object>("item5", 5) },
                                   DictionaryActorMethods.Enumerate(state, P()));
            ListsAreEqualUnordered(new String[] { "item2", "item3", "item4", "item5" },
                                   DictionaryActorMethods.EnumKeys(state, P()));
            ListsAreEqualUnordered(new Object[] { 2, 3, 4, 5 },
                                   DictionaryActorMethods.EnumValues(state, P()));

            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, P("item2")));
            ListsAreEqualUnordered(new KeyValuePair<String, Object>[] { new KeyValuePair<String, Object>("item3", 3), 
                                       new KeyValuePair<String, Object>("item4", 4), new KeyValuePair<String, Object>("item5", 5) },
                                   DictionaryActorMethods.Enumerate(state, P()));
            ListsAreEqualUnordered(new String[] { "item3", "item4", "item5" },
                                   DictionaryActorMethods.EnumKeys(state, P()));
            ListsAreEqualUnordered(new Object[] { 3, 4, 5 },
                                   DictionaryActorMethods.EnumValues(state, P()));

            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, P("item3")));
            ListsAreEqualUnordered(new KeyValuePair<String, Object>[] { new KeyValuePair<String, Object>("item4", 4), new KeyValuePair<String, Object>("item5", 5) },
                                   DictionaryActorMethods.Enumerate(state, P()));
            ListsAreEqualUnordered(new String[] { "item4", "item5" },
                                   DictionaryActorMethods.EnumKeys(state, P()));
            ListsAreEqualUnordered(new Object[] { 4, 5 },
                                   DictionaryActorMethods.EnumValues(state, P()));

            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, P("item4")));
            ListsAreEqualUnordered(new KeyValuePair<String, Object>[] { new KeyValuePair<String, Object>("item5", 5) },
                                   DictionaryActorMethods.Enumerate(state, P()));
            ListsAreEqualUnordered(new String[] { "item5" },
                                   DictionaryActorMethods.EnumKeys(state, P()));
            ListsAreEqualUnordered(new Object[] { 5 },
                                   DictionaryActorMethods.EnumValues(state, P()));

            Assert.AreEqual(1, (int)DictionaryActorMethods.Remove(state, P("item5")));
            ListIsEmpty((IList<KeyValuePair<String, Object>>)DictionaryActorMethods.Enumerate(state, P()));
            ListIsEmpty((IList<String>)DictionaryActorMethods.EnumKeys(state, P()));
            ListIsEmpty((IList<Object>)DictionaryActorMethods.EnumValues(state, P()));
        }

        [TestMethod]
        public void Dictionary_ValidationTest()
        {
            Console.WriteLine("Testing parameter validation.");
            IActorState state = ActorUnitTests.CreateActorState();

            DictionaryActorMethods.TryConstruct(state, new Object[] { "dictionary1", typeof(String).FullName, typeof(String).FullName });

            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Set, state, null);
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.Set, state, new Object[] { "dictionary1" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Set, state, new Object[] { null, "a", "b" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Set, state, new Object[] { "dictionary1", null, "b" });
            // Allow null values
            DictionaryActorMethods.Set(state, new Object[] { "dictionary1", "key", null });
            // Allow multiple values
            DictionaryActorMethods.Set(state, new Object[] { "dictionary1", "a", "b", "c" });

            /*
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.SetNew, state, null);
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.SetNew, state, new Object[] { "dictionary1" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.SetNew, state, new Object[] { null, "a", "b" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.SetNew, state, new Object[] { "dictionary1", null, "b" });
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.SetNew, state, new Object[] { "dictionary1", "a", "b", "c" });
            // Allow null values
            DictionaryActorMethods.SetNew(state, new Object[] { "dictionary1", "key", null });
            */

            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.MultiGet, state, null);
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.MultiGet, state, new Object[] { "dictionary1" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.MultiGet, state, new Object[] { null, "a" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.MultiGet, state, new Object[] { "dictionary1", null });

            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Get, state, null);
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.Get, state, new Object[] { "dictionary1" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Get, state, new Object[] { null, "a" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Get, state, new Object[] { "dictionary1", null });
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.Get, state, new Object[] { "dictionary1", "a", "b" });

            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.ContainsKey, state, null);
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.ContainsKey, state, new Object[] { "dictionary1" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.ContainsKey, state, new Object[] { null, "a" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.ContainsKey, state, new Object[] { "dictionary1", null });
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.ContainsKey, state, new Object[] { "dictionary1", "a", "b" });

            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Count, state, null);
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.Count, state, new Object[] { "dictionary1", "a" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Count, state, new Object[] { null });

            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.EnumKeys, state, null);
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.EnumKeys, state, new Object[] { "dictionary1", "a" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.EnumKeys, state, new Object[] { null });

            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Enumerate, state, null);
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.Enumerate, state, new Object[] { "dictionary1", "a" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Enumerate, state, new Object[] { null });

            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.EnumValues, state, null);
            ActorUnitTests.ExpectException<ArgumentException>(
                DictionaryActorMethods.EnumValues, state, new Object[] { "dictionary1", "a" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.EnumValues, state, new Object[] { null });

            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Remove, state, null);
            //ActorUnitTests.ExpectException<ArgumentException>(
            //    DictionaryActorMethods.Remove, state, new Object[] { "dictionary1" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Remove, state, new Object[] { null, "a" });
            ActorUnitTests.ExpectException<ArgumentNullException>(
                DictionaryActorMethods.Remove, state, new Object[] { "dictionary1", null });

            // Verify the type constraints on values work with multiple clients, and fail if we conflict
            DictionaryActorMethods.TryConstruct(state, new Object[] { "dictionary1", typeof(String).FullName, typeof(String).FullName });
            DictionaryActorMethods.TryConstruct(state, new Object[] { "dictionary2", typeof(String).FullName, typeof(Decimal).FullName });
            ActorUnitTests.ExpectException<InvalidOperationException>(
                DictionaryActorMethods.TryConstruct, state, new Object[] { "dictionary1", typeof(String).FullName, typeof(Int32).FullName });
            // Ensure that Destroy erases all traces of the type, so we can recreate the dictionary with a different name.
            DictionaryActorMethods.Destroy(state, new Object[] { "dictionary1" });
            DictionaryActorMethods.TryConstruct(state, new Object[] { "dictionary1", typeof(String).FullName, typeof(Random).FullName });
            // Ensure constructing multiple dictionary2's with the right types work as well, including a conflict on the key type.
            DictionaryActorMethods.TryConstruct(state, new Object[] { "dictionary2", typeof(String).FullName, typeof(Decimal).FullName });
            ActorUnitTests.ExpectException<InvalidOperationException>(
                DictionaryActorMethods.TryConstruct, state, new Object[] { "dictionary2", typeof(Random).FullName, typeof(Decimal).FullName });
        }


        #region Useful Test Methods

        private static void ListIsEmpty<T>(IList<T> list)
        {
            Assert.AreEqual(0, list.Count);
        }

        private static void ListsAreEqual<T>(IList<T> expected, Object result)
        {
            IList<T> otherList = (IList<T>)result;
            Assert.AreEqual(expected.Count, otherList.Count, "List lengths weren't identical");
            for (int i = 0; i < expected.Count; i++)
            {
                Assert.AreEqual(expected[i], otherList[i], "Element " + i + " was not equal");
            }
        }

        private static void ListsAreEqualUnordered<T>(IList<T> expected, Object result)
        {
            IList<T> otherList = (IList<T>)result;
            Assert.AreEqual(expected.Count, otherList.Count, "List lengths weren't identical");

            for (int i = 0; i < expected.Count; i++)
            {
                bool found = false;
                for (int j = 0; j < expected.Count; j++)
                {
                    if (Object.Equals(expected[i], otherList[j]))
                    {
                        found = true;
                        break;
                    }
                }
                Assert.IsTrue(found, String.Format("Couldn't find item {0} in result list", expected[i]));
            }
        }

        private static void ListsAreEqualUnordered<TKey, TValue>(IList<KeyValuePair<TKey, TValue>> expected, Object result)
        {
            IList<KeyValuePair<TKey, TValue>> otherList = (IList<KeyValuePair<TKey, TValue>>)result;
            Assert.AreEqual(expected.Count, otherList.Count, "List lengths weren't identical");

            for (int i = 0; i < expected.Count; i++)
            {
                TKey expectedKey = expected[i].Key;
                bool found = false;
                for (int j = 0; j < expected.Count; j++)
                {
                    if (expectedKey.Equals(otherList[j].Key))
                    {
                        found = true;
                        Assert.AreEqual(expected[i].Value, otherList[j].Value,
                            String.Format("For key {0}, value at index {1} should have been {2} but is {3}",
                                          expectedKey, i, expected[i].Value, otherList[j].Value));
                        break;
                    }
                }
                Assert.IsTrue(found, String.Format("Couldn't find item {0} in result list", expected[i]));
            }
        }

        /*
        private static void PairListsAreEqualUnordered<T>(IList<T> expected, Object result)
        {
            IList<T> otherList = (IList<T>)result;
            Assert.AreEqual(expected.Count, otherList.Count, "List lengths weren't identical");
            Assert.IsTrue(expected.Count % 2 == 0, "For a list of pairs, the length should be even!");

            for (int i = 0; i < expected.Count; i += 2)
            {
                T expectedKey = expected[i];
                bool found = false;
                for (int j = 0; j < expected.Count; j += 2)
                {
                    if (Object.Equals(expectedKey, otherList[j]))
                    {
                        found = true;
                        Assert.AreEqual(expected[i + 1], otherList[j + 1], 
                            String.Format("For key {0}, value at index {1} should have been {2} but is {3}",
                                          expectedKey, i + 1, expected[i + 1], otherList[j + 1]));
                        break;
                    }
                }
                Assert.IsTrue(found, String.Format("Couldn't find item {0} in result list", expected[i]));
            }
        }
        */
         
        #endregion Useful Test Methods
    }
}
